<?php

use app\common\encryption\AlphaID;
use app\model\MovieOrder as MovieOrderModel;
use think\facade\Db;
use think\facade\Log;
use think\facade\Request;

function curlGet($url, $header = null, $timeout = 5, $writeLog = false)
{
    $cache_key = 'curlGet' . $url . 'num';
    $curlTimeOUtCache = cache($cache_key);

    //三分钟内有两次拉取失败
    if ($curlTimeOUtCache && $curlTimeOUtCache >= 2) {
        doLog('curl error: ' . '网络超时过滤');
        return false;
    }
    $curl = curl_init();
    //设置选项，包括URL
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);   //只需要设置一个秒的数量就可以
    if ($header) {
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    }
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    //执行并获取HTML文档内容
    $data = curl_exec($curl);
    if (false === $data) {
        if (curl_errno($curl) == CURLE_OPERATION_TIMEDOUT) {
            $curlTimeOutNum = cache($cache_key) ?? 0;
            $curlTimeOutNum++;
            cache($cache_key, $curlTimeOutNum, 180); //超时记录
        }
        if (function_exists('doLog')) {
            doLog('curl error: ' . curl_error($curl));
        }
    }
    //释放curl句柄
    curl_close($curl);

    // 记录请求日志
    if ($writeLog) {
        \app\model\CurlRequestLog::addRecord([
            'url' => $url,
            'response' => $data,
        ]);
    }

    return $data;
}

function curlPost($url, $param, $header = null, $timeout = 5, $writeLog = true, $timeoutFiltering = true)
{

    $cache_key = 'curlPost' . $url . 'num';
    $curlTimeOUtCache = cache($cache_key);

    //三分钟内有两次拉取失败
    if ($curlTimeOUtCache && $curlTimeOUtCache >= 5 && $timeoutFiltering) {
        doLog('curl error: ' . '网络超时过滤');
        //todo..发送信息给业务

        return false;
    }

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);

    curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);   //只需要设置一个秒的数量就可以

    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    if ($header) {
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    }
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $param);
    $data = curl_exec($curl);

    $str = '';
    if (false === $data) {
        if (curl_errno($curl) == CURLE_OPERATION_TIMEDOUT) {
            $curlTimeOutNum = cache($cache_key) ?? 0;
            $curlTimeOutNum++;
            cache($cache_key, $curlTimeOutNum, 180); //超时记录
            $str .= '请求超时了';
            //todo..日志展示在首页或者运营看得比较清楚的位置

        }
        if (function_exists('doLog')) {
            doLog('curl error: ' . curl_error($curl));
        }
    }
    curl_close($curl);

    // 记录请求日志
//    if ($writeLog) {
//        \app\model\CurlRequestLog::addRecord([
//            'url' => $url,
//            'request' => is_array($param) ? json_encode($param, JSON_UNESCAPED_UNICODE) : $param,
//            'response' => $data ?? $str,
//        ]);
//    }

    return $data;
}

function success(string $message = '操作成功', $data = [])
{
    $data = [
        'code' => 200,
        'message' => $message,
        'data' => $data,
    ];

    Log::info('返回参数：' . json_encode($data, JSON_UNESCAPED_UNICODE));

    return json($data);
}

function fail(string $message = '操作失败，请重试或者联系我们', int $code = 0, $data = [])
{
    Log::info('错误返回：' . $message);
    return json([
        'code' => $code,
        'message' => $message,
        'data' => $data,
    ]);
}

/**
 * 身份证号码格式验证
 *
 * @param string $id_card 二代身份证号码
 *
 * @return bool true/false
 */
function checkIdCard(string $id_card): bool
{
    $id_card = strtoupper(trim($id_card));
    // 只能是18位
    if (18 != strlen($id_card)) {
        return false;
    }

    // 取出本体码
    $id_card_base = substr($id_card, 0, 17);

    // 取出校验码
    $verify_code = substr($id_card, 17, 1);

    // 加权因子
    $factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];

    // 校验码对应值
    $verify_code_list = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];

    // 根据前17位计算校验码
    $total = 0;
    for ($i = 0; $i < 17; ++$i) {
        $total += substr($id_card_base, $i, 1) * $factor[$i];
    }

    // 取模
    $mod = $total % 11;

    // 比较校验码
    if ($verify_code == $verify_code_list[$mod]) {
        return true;
    } else {
        return false;
    }
}

function checkMobile($mobile)
{
    return preg_match('/^1[3-9]\d{9}$/', $mobile);
}

/**
 * 金额：元 转 分.
 */
function yuan2fen($amount)
{
    if (empty($amount)) {
        return 0;
    }

    return intval(strval($amount * 100));
}

/**
 * 订单金额：分 转 元.
 */
function fen2yuan($amount)
{
    if (empty($amount)) {
        return 0;
    }

    return round(strval($amount / 100), 2);
}

/**
 * 生成签名.
 */
function getSign($params, $appSecret)
{
    if (isset($params['sign'])) {
        unset($params['sign']);
    }

    ksort($params);

    $sign = '';
    foreach ($params as $k => $v) {
        if ('' === $v || is_array($v)) {
            continue;
        }
        $sign .= $k . '=' . $v . '&';
    }
    $sign .= 'app_secret=' . $appSecret;
    return strtolower(md5($sign));
}

/**
 * 生成话费充值订单号.
 */
function generateMobileOrderId()
{
    for ($i = 0; $i < 21; ++$i) {
        $orderId = date('ymdHis') . str_pad(mt_rand(0, 99999), 5, STR_PAD_LEFT);
        $id = Db::name('mobile_order')
            ->where('order_id', $orderId)
            ->value('id');
        if (empty($id)) {
            return $orderId;
        }
    }

    return false;
}

/**
 * 生成订单编号
 * VD:(视频).
 */
function generateCouponOrderId($sub = '')
{
    for ($i = 0; $i < 21; ++$i) {
        $orderId = date('ymdHis') . str_pad(mt_rand(0, 99999), 5, STR_PAD_LEFT);
        $id = Db::name('order')
            ->where('sn', $orderId)
            ->value('id');
        if (empty($id)) {
            return $orderId;
        }
    }

    return false;
}

/**
 * 生成订单号.
 * 油卡，电费
 */
function generateOrderId($prefix, $table)
{
    for ($i = 0; $i < 21; ++$i) {
        $orderId = $prefix . date('ymdHis') . str_pad(mt_rand(0, 99999), 5, STR_PAD_LEFT);
        $id = Db::name($table)
            ->where('order_id', $orderId)
            ->value('id');
        if (empty($id)) {
            return $orderId;
        }
    }

    return false;
}


function getOrderSn($prefix = '', $subfix = '')
{
    $pid = getmypid();
    $microtime = microtime(true);
    if (strlen($pid) <= 5) {
        $sn = $prefix . date('YmdHis') . (explode('.', $microtime)[1]) . str_pad($pid, 5, '0', STR_PAD_LEFT) . $subfix;
    } else {
        // todo 优化
        $sn = $prefix . date('ymdHis') . (explode('.', $microtime)[1]) . mt_rand(100000, 999999) . $subfix;
    }

    return $sn;
}

/**
 * 返回字符串 移动联通电信
 * @param $mobile
 * @return string
 */
function getMobileStr($mobile)
{
    $map = [
        1 => '移动',
        2 => '联通',
        3 => '电信',
        -1 => '未知',
    ];
    return $map[getMobileIsp($mobile)]??'';
}


/**
 * 根据号码段判断手机号运营商.
 *
 * https://zhuanlan.zhihu.com/p/40878967
 *
 * "/^(?:134|135|136|137|138|139|147|148|150|151|152|157|158|159|172|178|182|183|184|187|188|195|197|198)\d{8}$/"; //移动
130|131|132|145|155|156|166|175|176|185|186|196)
 * 133|1349|149|153|162|177|173|180|181|189|190|191|193|199
 */
function getMobileIsp($mobile)
{
    $list = [
        // 移动
        1 => [
            134, 135, 136, 137, 138, 139,
            144, 147, 148,
            150, 151, 152, 157, 158, 159,
            165,
            178,172,
            182, 183, 184, 187, 188,
            198,195,197
        ],
        // 联通
        2 => [
            130, 131, 132,
            140, 145, 146,
            155, 156,
            166, 167,
            171, 175, 176,
            185, 186,
            196
        ],
        // 电信
        3 => [
            133,
            162,
            141, 149,
            153,
            173, 177,
            180, 181, 189, 191, 199,
            190,
            193,
        ],
    ];

    $four = substr($mobile, 0, 4);
    if ('1349' == $four) {
        return 3;
    }
    $three = substr($mobile, 0, 3);
    foreach ($list as $k => $v) {
        if (in_array($three, $v)) {
            return $k;
        }
    }

    return -1;
}

/*
 自定义验证
*/
function dmjValidate($rules, $message, $data, $batch = false, $failException = false)
{
    $validate = validate($rules, $message, $batch, $failException);
    $res = $validate->check($data);
    if (!$res) {
        return $validate->getError();
    }

    return '';
}

/**
 * @desription 写日志
 */
function doLog($msg, $level = 'info')
{
    if ('string' != gettype($msg)) {
        $msg = json_encode($msg, JSON_UNESCAPED_UNICODE);
    }
    $msg = 'url=【' . (Request::url()) . '】,request_id:' . REQUEST_ID . ',耗时：' . (microtime(true) - TP_START) . ',msg:' . $msg;

    return Log::{$level}($msg);
}

/**
 * 获取异常统一格式返回.
 */
function getExceptionMsg($e)
{
    return $e->getMessage() . ',' . $e->getFile() . '(' . $e->getLine() . ')';
}

/**
 * 驼峰转下划线格式.
 */
function uncamelize($camelCaps, $separator = '_')
{
    return strtolower(preg_replace('/([a-z])([A-Z])/', '$1' . $separator . '$2', $camelCaps));
}

/**
 * 下划线转驼峰
 * 思路:
 * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
 * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
 */
function camelize($uncamelized_words, $separator = '_')
{
    $uncamelized_words = $separator . str_replace($separator, ' ', strtolower($uncamelized_words));

    return ltrim(str_replace(' ', '', ucwords($uncamelized_words)), $separator);
}

/*
 批量下划线转驼峰
 */
function batchCamelize($arr)
{
    $ret = [];
    if (!$arr) {
        return $ret;
    }
    foreach ($arr as $k => $v) {
        $ret[camelize($k)] = $v;
    }

    return $ret;
}

/*
 驼峰转下划线格式
 */
function batchUncamelize($arr)
{
    $ret = [];
    if (!$arr) {
        return $ret;
    }
    foreach ($arr as $k => $v) {
        $ret[uncamelize($k)] = $v;
    }

    return $ret;
}

/*
 预警 ,目前写入 warning日志
*/
function doWarning($msg)
{
    return doLog($msg, 'warning');
}

/**
 * 从service返回的数组解析返回响应.
 */
function serviceResponse($data)
{
    if ($data['code']) { // CommonService 约定 成功的code是 0
        return fail($data['msg'], 0, []);
    } else {
        return success('', $data['data']);
    }
}

function sendSms($content, $mobile)
{
    if (is_array($mobile)) {
        $mobile = implode(',', $mobile);
    }

    if (!$mobile || !$content) {
        return ['code' => 500, 'msg' => '发送失败，手机号或者发送消息为空'];
    }

    // todo 非线上环境 发送短信手机号限制
    if (!isProd()) {
        $whiteList = [];   // 短信白名单
        $directList = ['18922396855']; // 不发送直接返送成功名单
        // 此处的手机号直接返回成功 ，不做实际发送短信
        if (in_array($mobile, $directList)) {
            return ['code' => 0, 'msg' => '发送成功', 'data' => ['msgid' => $res['msgid'] ?? '']];
        } else {
            if (!in_array($mobile, $whiteList)) {
                return ['code' => 500, 'msg' => '为防止误操作，非在线环境发送短信需要添加白名单', 'data' => ['msgid' => $res['msgid'] ?? '']];
            }
        }
    }

    // todo 消息长度 ，手机号数量限制处理

    $param = [
        'uid' => '3389',
        'pwd' => 'xmlxkj02123456',
        'mobile' => $mobile,
        'content' => $content,
    ];

    $url = 'http://www.aozhongyun.com/Admin/index.php/Message/send';
    $param = json_encode($param, JSON_UNESCAPED_UNICODE);
    $header = ['Content-Type: application/json; charset=utf-8', 'Content-Length: ' . strlen($param)];
    $res = curlPost($url, $param, $header);
    doLog('发送短息，请求：' . $param . '，返回：' . $res);
    $res = json_decode($res, true);
    if ($res) {
        if ($res['respCode']) {
            return ['code' => $res['respCode'], 'msg' => $res['respMsg'], 'data' => ['msgid' => $res['msgid'] ?? '']];
        }

        return ['code' => 0, 'msg' => '发送成功', 'data' => ['msgid' => $res['msgid'] ?? '']];
    }

    return ['code' => 500, 'msg' => '发送失败', 'data' => ['msgid' => !empty($res['msgid']) ? $res['msgid'] : '']];
}

/**
 * 判断微客云快充94折是否在有效下单时间内
 * 工作日：09:00-12:00，13:00-19:00.
 *
 * @return false不可下单/true可以下单【已废弃】
 */
function validateWikeyun94Fast()
{
    // 时间判断
    $time = date('H:m');
    if ($time < '09:00') {
        return false;
    }
    if ($time > '11:55' && $time < '13:00') {
        return false;
    }
    if ($time > '18:55') {
        return false;
    }

    // 周一到周五
    $week = date('w');
    if ($week < 1 || $week > 5) {
        return false;
    }

    // 排除法定节假日
    $holiday = [
        // 国庆
        '2021-10-01', '2021-10-02', '2021-10-03', '2021-10-04', '2021-10-05', '2021-10-06', '2021-10-07',
        // 元旦
        '2021-12-31', '2022-01-01', '2022-01-02',
        // 春节
        '2022-01-31', '2022-02-01', '2022-02-02', '2022-02-03', '2022-02-04', '2022-02-05', '2022-02-06',
    ];
    $today = date('Y-m-d');
    if (in_array($today, $holiday)) {
        return false;
    }

    return true;
}

/**
 * 是否是生产环境.
 */
function isProd()
{
    return 'prod' === config('app.app_env');
}

/**
 * 是否是本地环境.
 */
function isLocal()
{
    return 'local' === config('app.app_env');
}


/**
 * 是否是测试环境.
 */
function isTesting()
{
    return 'testing' === config('app.app_env');
}

/*
 * url 参数替换
 */
function urlParamReplace($url, $name, $value)
{
    $arr = parse_url($url);

    if (!empty($arr['query'])) {
        parse_str($arr['query'], $query);
        if (!empty($query[$name])) {
            $url = str_replace($query[$name], $value, $url);
        } else {
            $url .= '&' . $name . '=' . $value;
        }
    } else {
        $url .= '?' . $name . '=' . $value;
    }

    return $url;
}

/**
 * url 参数参数.
 */
function urlParamRemove($url, $var)
{
    $url = preg_replace('/([?&])' . $var . '=[^&]+(&|$)/', '$1', $url);
    $url = trim($url, '?#&');

    return $url;
}

/*
 计算通道费用
*/
function supplierGateAmount($amount, $gateRate)
{
    return intval(strval($amount * $gateRate / 100));
}

/*
 计算平台利润
 supplierProfit 根据结算方式计算后的利润部分 ，目前用代理商利润计算方法 calcAgentProfit，并传供应商对应的配置参数
*/
function calcProfit($supplierProfit, $agentProfit, $gateAmount)
{
    return $supplierProfit - $agentProfit - $gateAmount;
}

/*
 计算代理商利润
 originAmount 面额
 amount 用户实际支付的价格
*/
function calcAgentProfit($settleType, $settleValue, $originAmount, $amount)
{
    return $amount - intval($originAmount * $settleValue / 100);
}

/*
 计算佣金 类似滴滴加油，支付在第三方的
commiRate 返佣比例 %
amount 付费金额
*/
function calcOilCommiss($commiRate, $amount)
{
    return intval($commiRate * $amount / 100);
}

/*
 获取业务类型里 serType 对应 数组字段
*/
function getServTypeKeyMap($col = 'name')
{
    return array_combine(array_keys(PRODUCT_SERV_TYPE), array_column(PRODUCT_SERV_TYPE, $col));
}

/**
 * 数组转xml.
 */
function arr2xml($data)
{
    $str = '';
    foreach ($data as $key => $val) {
        // 去掉key中的下标[]
        $key = preg_replace('/\[\d*\]/', '', $key);
        if (is_array($val)) {
            $child = arr2xml($val);

            $str .= "<$key>$child</$key>";
        } else {
            $str .= "<$key>$val</$key>";
        }
    }

    return $str;
}

/**
 * xml转数组.
 */
function xml2arr($xml)
{
    try {
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $val = json_decode(json_encode($xmlstring), true);
    } catch (\Exception $e) {
        return false;
    }

    return $val;
}

function my_number_format(&$value, $key)
{
    $value = number_format($value, 2);
}

/**
 * Swoole 协程 HTTP 客户端
 *
 * @param   $method get/post
 * @param   $url
 * @param   $data
 * @param   $header
 */
function swooleHttpClient($method, $url, $data = null, $header = [], $options = [])
{
    $url = parse_url($url);
    if (!isset($url['scheme']) || !isset($url['host'])) {
        return false;
    }
    $port = 80;
    if (isset($url['port'])) {
        $port = $url['port'];
    } elseif ($url['scheme'] == 'https') {
        $port = 443;
    }

    $cli = new \Swoole\Coroutine\Http\Client($url['host'], $port, $url['scheme'] == 'https');
    if ($header) {
        $cli->setHeaders($header);
    }
    if ($options) {
        $cli->set($options);
    }
    if ($method == 'get') {
        $cli->get($url['path'] ?? '/');
    } else {
        $cli->post($url['path'] ?? '/', $data);
    }
    $result = $cli->body;
    $cli->close();

    return $result;
}

/**
 * 返回两个时间的相距时间，*年*月*日*时*分*秒
 * @param int $one_time 时间一
 * @param int $two_time 时间二
 * @param int $return_type 默认值为0，0/不为0则拼接返回，1/*秒，2/*分*秒，3/*时*分*秒/，4/*日*时*分*秒，5/*月*日*时*分*秒，6/*年*月*日*时*分*秒
 * @param array $format_array 格式化字符，例，array('年', '月', '日', '时', '分', '秒')
 * @return String or false
 */
function getRemainderTime($one_time, $two_time, $return_type = 0, $format_array = array('年', '个月', '天', '时', '分', '秒'))
{
    if ($return_type < 0 || $return_type > 6) {
        return false;
    }


    if (!(is_int($one_time) && is_int($two_time))) {
        return false;
    }
    $remainder_seconds = abs($one_time - $two_time);
    //年
    $years = 0;
    if (($return_type == 0 || $return_type == 6) && $remainder_seconds - 31536000 > 0) {
        $years = floor($remainder_seconds / (31536000));
    }
    //月
    $monthes = 0;
    if (($return_type == 0 || $return_type >= 5) && $remainder_seconds - $years * 31536000 - 2592000 > 0) {
        $monthes = floor(($remainder_seconds - $years * 31536000) / (2592000));
    }
    //日
    $days = 0;
    if (($return_type == 0 || $return_type >= 4) && $remainder_seconds - $years * 31536000 - $monthes * 2592000 - 86400 > 0) {
        $days = floor(($remainder_seconds - $years * 31536000 - $monthes * 2592000) / (86400));
    }
    //时
    $hours = 0;
    if (($return_type == 0 || $return_type >= 3) && $remainder_seconds - $years * 31536000 - $monthes * 2592000 - $days * 86400 - 3600 > 0) {
        $hours = floor(($remainder_seconds - $years * 31536000 - $monthes * 2592000 - $days * 86400) / 3600);
    }
    //分
    $minutes = 0;
    if (($return_type == 0 || $return_type >= 2) && $remainder_seconds - $years * 31536000 - $monthes * 2592000 - $days * 86400 - $hours * 3600 - 60 > 0) {
        $minutes = floor(($remainder_seconds - $years * 31536000 - $monthes * 2592000 - $days * 86400 - $hours * 3600) / 60);
    }
    //秒
    $seconds = $remainder_seconds - $years * 31536000 - $monthes * 2592000 - $days * 86400 - $hours * 3600 - $minutes * 60;
    $return = false;
    switch ($return_type) {
        case 0:
            if ($years > 0) {
                $return = $years . $format_array[0] . $monthes . $format_array[1] . $days . $format_array[2] . $hours . $format_array[3] . $minutes . $format_array[4] . $seconds . $format_array[5];
            } else if ($monthes > 0) {
                $return = $monthes . $format_array[1] . $days . $format_array[2] . $hours . $format_array[3] . $minutes . $format_array[4] . $seconds . $format_array[5];
            } else if ($days > 0) {
                $return = $days . $format_array[2] . $hours . $format_array[3] . $minutes . $format_array[4] . $seconds . $format_array[5];
            } else if ($hours > 0) {
                $return = $hours . $format_array[3] . $minutes . $format_array[4] . $seconds . $format_array[5];
            } else if ($minutes > 0) {
                $return = $minutes . $format_array[4] . $seconds . $format_array[5];
            } else {
                $return = $seconds . $format_array[5];
            }
            break;
        case 1:
            $return = $seconds . $format_array[5];
            break;
        case 2:
            $return = $minutes . $format_array[4] . $seconds . $format_array[5];
            break;
        case 3:
            $return = $hours . $format_array[3] . $minutes . $format_array[4] . $seconds . $format_array[5];
            break;
        case 4:
            $return = $days . $format_array[2] . $hours . $format_array[3] . $minutes . $format_array[4] . $seconds . $format_array[5];
            break;
        case 5:
            $return = $monthes . $format_array[1] . $days . $format_array[2] . $hours . $format_array[3] . $minutes . $format_array[4] . $seconds . $format_array[5];
            break;
        case 6:
            $return = $years . $format_array[0] . $monthes . $format_array[1] . $days . $format_array[2] . $hours . $format_array[3] . $minutes . $format_array[4] . $seconds . $format_array[5];
            break;
        default:
            $return = false;
    }
    return $return;
}

/**
 * 处理默认值
 */
function handleParameters(array $origins, array $defaults, array $params)
{

    foreach ($defaults as $filed => $default) {
        if (empty($params[$filed]) && !empty($default)) {
            $origins[$filed] = $default;
            continue;
        }
        if (!empty($params[$filed])) {
            $origins[$filed] = $params[$filed];
        }
    }
    return $origins;
}

/*
 * 根据经纬度计算距离
 * 地图计算距离
 *  $lat1：起点纬度
 *  $lng1：起点经度
 *
 *  $lat2：终点纬度
 *  $lng2：终点经度
 *  单位 默认 千米 需要米 请传$unitMeter true;
 * */
function latLngMapApiDistance($lat1, $lng1, $lat2, $lng2, $unitMeter = false)
{
    // 将角度转为狐度
    $radLat1 = deg2rad($lat1); // deg2rad()函数将角度转换为弧度
    $radLat2 = deg2rad($lat2);
    $radLng1 = deg2rad($lng1);
    $radLng2 = deg2rad($lng2);
    $a = $radLat1 - $radLat2;
    $b = $radLng1 - $radLng2;
    $s = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2))) * 6378.137;
    $dis = bcadd($s, 0, 2);
    if ($unitMeter) {
        $dis = $dis * 1000;
        return $dis;
    }
    return $dis;
}

/**
 * xml转数组
 * @return array
 * @author ymzhang
 * date 2022-06-28
 * time 17:00
 */
function xmlToJson($xml)
{
    if (empty($xml)) {
        return [];
    }
    $xml = simplexml_load_string($xml);                         //xml转object
    return json_encode($xml, JSON_UNESCAPED_UNICODE);      //objecct转json
}

/**
 * 返回统一格式
 * @return array|bool
 * @author ymzhang
 * date 2022-06-29
 * time 09:00
 */
function web_request(array $data, bool $status, int $code, string $message)
{
    return ['data' => $data, 'status' => $status, 'code' => $code, 'message' => $message];
}

/**
 * 获取13位时间戳
 * @return int
 * @author ymzhang
 * date 2022-06-29
 * time 17:25
 */
function msectime()
{
    list($msec, $sec) = explode(' ', microtime());
    $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
    return intval($msectime);
}

/**
 * Notes:数字签名计算方式
 * User: ymzhang
 * Date: 2022/06/28
 * Time: 15:45
 * @return string
 */
function generateSign()
{
    $numargs = func_num_args();
    $arg_list = func_get_args();
    $sign = '';
    for ($i = 0; $i < $numargs; $i++) {
        $sign .= $arg_list[$i];
    }
    return strtolower(md5($sign));
}

/**
 * 将一个字串中含有全角的数字字符、字母、空格或'%+-()'字符转换为相应半角字符
 * @access public
 * @param string $str 待转换字串
 * @return string $str 处理后字串
 * @date 2022-07-06
 * @time 17:35
 * @author ymzhang
 */
function make_semiangle($str)
{
    $arr = array('０' => '0', '１' => '1', '２' => '2', '３' => '3', '４' => '4',
        '５' => '5', '６' => '6', '７' => '7', '８' => '8', '９' => '9',
        'Ａ' => 'A', 'Ｂ' => 'B', 'Ｃ' => 'C', 'Ｄ' => 'D', 'Ｅ' => 'E',
        'Ｆ' => 'F', 'Ｇ' => 'G', 'Ｈ' => 'H', 'Ｉ' => 'I', 'Ｊ' => 'J',
        'Ｋ' => 'K', 'Ｌ' => 'L', 'Ｍ' => 'M', 'Ｎ' => 'N', 'Ｏ' => 'O',
        'Ｐ' => 'P', 'Ｑ' => 'Q', 'Ｒ' => 'R', 'Ｓ' => 'S', 'Ｔ' => 'T',
        'Ｕ' => 'U', 'Ｖ' => 'V', 'Ｗ' => 'W', 'Ｘ' => 'X', 'Ｙ' => 'Y',
        'Ｚ' => 'Z', 'ａ' => 'a', 'ｂ' => 'b', 'ｃ' => 'c', 'ｄ' => 'd',
        'ｅ' => 'e', 'ｆ' => 'f', 'ｇ' => 'g', 'ｈ' => 'h', 'ｉ' => 'i',
        'ｊ' => 'j', 'ｋ' => 'k', 'ｌ' => 'l', 'ｍ' => 'm', 'ｎ' => 'n',
        'ｏ' => 'o', 'ｐ' => 'p', 'ｑ' => 'q', 'ｒ' => 'r', 'ｓ' => 's',
        'ｔ' => 't', 'ｕ' => 'u', 'ｖ' => 'v', 'ｗ' => 'w', 'ｘ' => 'x',
        'ｙ' => 'y', 'ｚ' => 'z',
        '（' => '(', '）' => ')', '〔' => '[', '〕' => ']', '【' => '[',
        '】' => ']', '〖' => '[', '〗' => ']', '“' => '"', '”' => '"',
        '‘' => "'", '’' => "'", '｛' => '{', '｝' => '}', '《' => '<',
        '》' => '>', '％' => '%', '＋' => '+', '—' => '-', '－' => '-',
        '～' => '-', '：' => ':', '。' => '.', '、' => ',', '，' => '.',
        '；' => ';', '？' => '?', '！' => '!', '…' => '-', '‖' => '|',
        '＂' => '"', '　' => ' ', '＇' => "'", '￥' => "$");
    return strtr($str, $arr);
}


/**
 * 获取键对应的值
 * @param array $array 源数组
 * @param array $keys 要提取的键数组
 * @param string $index 二维组中指定提取的字段（唯一）
 * @return array
 * @author ymzhang
 * @date 2022-07-12
 * @time 09:55
 */
function array_keys_search($array, $keys, $index = '')
{
    if (empty($array))
        return $array;
    if (!empty($index) && count($array) != count($array, COUNT_RECURSIVE))
        $array = array_column($array, null, $index);
    $list = array();
    foreach ($keys as $key) {
        if (isset($array[$key]))
            $list[$key] = $array[$key];
    }
    return $list;
}

/**
 * 根据支付时间，获取结算时间
 * 结算时间：次月25号
 */
function getSettleDate($payTime)
{
    $year = substr($payTime, 0, 4);
    $month = substr($payTime, 5, 2) + 1;
    return date('Y-m-d', mktime(0, 0, 0, $month, 25, $year));
}


/**
 * 获取中间跳转链接
 * @return array|mixed|string|string[]
 */
function getRedirectUrl()
{

    $redirectUrl = input('redirect_url', '');
    $host = env('app.api_url');

    $redirectUrl = str_replace('#', 'ymhcccc', $redirectUrl);

    if (!empty($redirectUrl)) {
        Log::info('前端请求支付时候的url：' . $redirectUrl);
        Log::info('前端请求支付时候的host：' . request()->url());
        if (strstr($redirectUrl, 'http')) {
            $redirectUrl = $redirectUrl . '&backIndex=1';
            $redirectUrl = $host . '/api/v2.wechat/authRedirect?url=' . urlencode($redirectUrl);

        } else {
            $redirectUrl = urlencode(request()->domain() . $redirectUrl . '&backIndex=1');
        }
    }

    return $redirectUrl;
}


/**
 * id 加解密
 * @param $data
 */
function alphaID($data)
{

    $alphaIDObj = new \app\common\service\encryption\AlphaID();

    if (is_numeric($data)) {
        return $alphaIDObj->alphaID($data, false, MovieOrderModel::PASSKEY_LENGTH, MovieOrderModel::PASSKEY_SALT);//盐之前用了电影票的，现在共用了，不管他啦
    }

    return $alphaIDObj->alphaID($data, true, MovieOrderModel::PASSKEY_LENGTH, MovieOrderModel::PASSKEY_SALT);

}

function bubble_sort($arr)
{
    $len = count($arr);
    for ($i = 0; $i < $len - 1; $i++) {//循环对比的轮数
        for ($j = 0; $j < $len - $i - 1; $j++) {
            //当前轮相邻元素循环对比
            if ($arr[$j] > $arr[$j + 1]) {//如果前边的大于后边的
                $tmp = $arr[$j];//交换数据
                $arr[$j] = $arr[$j + 1];
                $arr[$j + 1] = $tmp;
            }
        }
    }
    return $arr;
}

//判断有几位小数
function getDecimalLen($num)
{
    $arr = explode('.', $num);

    $str = array_pop($arr);

    return strlen($str);
}

/**
 * 检查QQ号码是否合法
 */
function checkQQ($qq)
{
    return preg_match('/[1-9]\\d{4,14}/', $qq);
}

/**
 * +----------------------------------------------------------
 * 产生随机字串，可用来自动生成密码 默认长度6位 字母和数字混合
 * +----------------------------------------------------------
 * @param string $len 长度
 * @param string $type 字串类型
 * 0 字母 1 数字 其它 混合
 * @param string $addChars 额外字符
 * +----------------------------------------------------------
 * @return string
 * +----------------------------------------------------------
 */
function randomString($len = 6, $type = '', $addChars = '')
{
    $str = '';
    switch ($type) {
        case 0:
            $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' . $addChars;
            break;
        case 1:
            $chars = str_repeat('0123456789', 3);
            break;
        case 2:
            $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . $addChars;
            break;
        case 3:
            $chars = 'abcdefghijklmnopqrstuvwxyz' . $addChars;
            break;
        case 4:
            $chars = "们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航衣孙龄岭骗休借" . $addChars;
            break;
        default:
            // 默认去掉了容易混淆的字符oOLl和数字01，要添加请使用addChars参数
            $chars = 'ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' . $addChars;
            break;
    }
    if ($len > 10) { //位数过长重复字符串一定次数
        $chars = $type == 1 ? str_repeat($chars, $len) : str_repeat($chars, 5);
    }
    if ($type != 4) {
        $chars = str_shuffle($chars);
        $str = substr($chars, 0, $len);
    } else {
        // 中文随机字
        for ($i = 0; $i < $len; $i++) {
            $str .= msubstr($chars, floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)), 1);
        }
    }
    return $str;
}

function getTree(&$origionArr, $p_id = 0)
{
    $result = [];

    foreach ($origionArr as $value) {
        if ($value['pid'] !== $p_id) continue;

        $value['children'] = getTree(
            $origionArr,
            $value['id']
        );

        $result[] = $value;
    }

    return $result;
}

/**
 * 获取树中的选择id
 * @param array $datas
 * @return array
 */
function getSelect(array $datas){
    $ids = [];
    foreach ($datas as $permission){
        if (!empty($permission['select'])){
            $ids[] = $permission['id'];
        }
        if (!empty($permission['children'])){
            foreach (getSelect($permission['children']) as $v){
                $ids[] = $v;
            }
        }
    }
    return $ids;
}




